Skip to content

Conversation

@WaVEV
Copy link
Collaborator

@WaVEV WaVEV commented Nov 20, 2025

Generated query:

[{'$collStats': {}},
 {'$lookup': {'as': 'wrapped',
              'from': 'aggregation_author',
              'pipeline': [{'$group': {'_id': None,
                                       'count': {'$sum': {'$cond': {'else': 1,
                                                                    'if': {'$in': [{'$type': '$_id'},
                                                                                   ['missing',
                                                                                    'null']]},
                                                                    'then': None}}}}}]}},
 {'$replaceWith': {'$cond': [{'$eq': ['$wrapped', []]}, {}, {'$first': '$wrapped'}]}},
 {'$project': {'count': {'$ifNull': ['$count', {'$literal': 0}]}}}]

@aclark4life
Copy link
Collaborator

Awesome, thank you and thanks @asya999

Copy link
Collaborator

@aclark4life aclark4life left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test, particular one that would test something that breaks in the Django admin with QE (even though QE is not merged yet)?

}
)
pipeline.append({"$group": group})
# It may be a bug, $$NOW has to be called to be reachable in the rest of the pipeline.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add link to the SERVER ticket and add an explanatory comment about the purpose of the $unionWith clause.

I think we can also mention it in the release notes as a performance improvement since the team said $facet prevents the use of optimizations.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly, this cannot be implemented as it is.
To handle the global aggregation and the default values (for example:

SELECT coalesce(avg(age), 35) FROM people WHERE age > 100;

we need to wrap the aggregation so MongoDB always returns a single document.
This is done by wrapping the pipeline inside a lookup. Example:

db.z.aggregate([
    { $collStats: {} },
    { $lookup: { from: "z", as: "wrap", pipeline: [...pipeline stages] } },
    { $replaceWith: {"$cond": [{"$eq": ["$wrap", []]}, {}, {$first: "$wrap"}]}}
])

It’s not very intuitive use of $collStats, but it works 😄. It replaces the need for $unionWith.
$collStats is used as a pivot so we can apply the required operator after the group result.

@Jibola
Copy link
Contributor

Jibola commented Nov 21, 2025

Can you provide, in this PR, an example of what the removal of $facet makes the new query signatures look like?

@WaVEV WaVEV force-pushed the INTPYTHON-833-Refactor-Remove-$facet-usage-in-aggregation-pipeline branch from 3e2c32d to 273957f Compare November 25, 2025 03:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants